﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Traders.Controllers;

namespace Traders.Models
{
    class OpenTradesModel : TradersModel
    {
        #region Podstawowe inicjalizacje z interfejsu TradersModel

        private DataColumn[] _columns = {
                                new DataColumn("Broker", typeof(string)),
                                new DataColumn("Account", typeof(string)),
                                new DataColumn("Ticket", typeof(int)),
                                new DataColumn("Symbol", typeof(string)),
                                new DataColumn("Type", typeof(int)),
                                new DataColumn("Stop Loss", typeof(double)),
                                new DataColumn("Take Profit", typeof(double)),
                                new DataColumn("Open Price", typeof(double)),
                                new DataColumn("Open Time", typeof(DateTime)),
                                new DataColumn("Order Profit", typeof(double)),
                                new DataColumn("Currency", typeof(string)),
                                new DataColumn("Magic", typeof(int))
                                };

        private DataColumn getColumn(string Name)
        {
            var column =
                from c in _columns
                where c.ColumnName == Name
                select c;

            return column.First();
        }

        public DataColumn[] DataColumns { get { return _columns; } }

        private bool _initialized = false;
        public Boolean Initialized { get { return _initialized; } }

        private DataTable _dataTable = new DataTable();
        public DataTable DataTable
        {
            get { return _dataTable; }
        }

        public void doTicks(int miliseconds)
        {
            refreshAccountsTrades();
        }

        #endregion

        #region Inicjalizacje eventów z interfejsu

        public event EventHandler<TradersEventArgs> EventHandler;

        public void FireEvent(TradersEventArgs e)
        {
            if (EventHandler != null)
                EventHandler(this, e);
        }

        public void HandleEvent(object sender, TradersEventArgs e)
        {
            switch (e.Action)
            {
                case "AccountConnected":
                    if (e.Tag is Account) AddAccountTrades((Account)e.Tag);
                    else throw new Exception("Błędny parametr Tag przy wywołaniu eventu AccountAdded");
                    break;
                case "ConnectionSuccess":
                    _initialized = true;
                    break;
                case "CloseTradeClicked":
                    if (e.Tag is DataGridViewSelectedRowCollection) CloseTrades((DataGridViewSelectedRowCollection)e.Tag);
                    else throw new Exception("Błąd przy zamykaniu zlecenia - błędny parametr Tag");
                    break;
            }
        }

        #endregion


        #region Metody obsługujące eventy

        private void AddAccountTrades(Account acc)
        {
            var trades = acc.getOpenTrades();

            foreach (var trade in trades)
            {
                _dataTable.Rows.Add(
                    acc.Broker,
                    acc.Login,
                    trade.GetTicket(),
                    trade.GetSymbol(),
                    trade.GetTradeOperation(),
                    trade.GetStopLoss(),
                    trade.GetTakeProfit(),
                    trade.GetOpenPrice(),
                    trade.GetOpenTime(),
                    trade.GetProfit(),
                    acc.Strategy.AccountCurrency(),
                    trade.GetMagic()
                );
            }

        }

        private void CloseTrades(DataGridViewSelectedRowCollection selectedRows)
        {
            foreach (DataGridViewRow row in selectedRows)
            {
                Account acc = this.AccountManager.GetAccount((string)row.Cells["Broker"].Value, (string)row.Cells["Account"].Value);
                if (!acc.CloseTrade((int)row.Cells["Ticket"].Value))
                {
                    TradersEventArgs e = new TradersEventArgs();
                    e.Action = "CloseTradeError";
                    e.Tag = (int)row.Cells["Ticket"].Value;
                    FireEvent(e);
                    Console.WriteLine("CloseTradeError");
                }
                    
            }
        }

        #endregion

        private AccountManager AccountManager { get; set; }

        public OpenTradesModel(AccountManager manager)
        {
            this.AccountManager = manager;
            foreach (var c in _columns) _dataTable.Columns.Add(c);
            DataColumn[] PrimaryKeys = { getColumn("Broker"), getColumn("Account"), getColumn("Ticket") };
            _dataTable.PrimaryKey = PrimaryKeys;
        }


        private void refreshAccountsTrades()
        {
            if (!_initialized) return;

            foreach (Account a in AccountManager.Accounts)
            {
                var updatedTrades = a.getOpenTrades();

                foreach (var trade in updatedTrades)
                {
                    object[] keys = { a.Broker, a.Login, trade.GetTicket() };
                    DataRow row = _dataTable.Rows.Find(keys);

                    if (row == null)
                    {
                        // robimy inserta
                        _dataTable.Rows.Add(
                            a.Broker,
                            a.Login,
                            trade.GetTicket(),
                            trade.GetSymbol(),
                            trade.GetTradeOperation(),
                            trade.GetStopLoss(),
                            trade.GetTakeProfit(),
                            trade.GetOpenPrice(),
                            trade.GetOpenTime(),
                            trade.GetProfit(),
                            a.Strategy.AccountCurrency(),
                            trade.GetMagic()
                        );
                    }
                    else
                    {
                        // robimy update
                        row.SetField(getColumn("Stop Loss"), trade.GetStopLoss());
                        row.SetField(getColumn("Take Profit"), trade.GetTakeProfit());
                        row.SetField(getColumn("Order Profit"), trade.GetProfit());
                    }


                }

                DataRow[] oldTrades = _dataTable.Select(String.Format("Broker = '{0}' AND Account = '{1}'", a.Broker, a.Login));

                foreach (var trade in oldTrades)
                {
                    int ticket = trade.Field<int>("Ticket");
                    if (!updatedTrades.Exists(order => order.GetTicket() == ticket))
                    {
                        trade.Delete();
                    }
                }



            }

        }



    }
}
